package verda.kvantumo.Itala_Esperanta_Vortaro;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import verda.kvantumo.Itala_Esperanta_Vortaro.R;
import verda.kvantumo.Itala_Esperanta_Vortaro.DBAdapter;
import verda.kvantumo.Itala_Esperanta_Vortaro.S;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;

public class main extends Activity {
	private String olda = "";
	private int olda_id = 0;
	private int startIndekso = 0;
	private final int vidIntervalo = 100;
	/**
	 * La aro da ŝarĝitaj vortoj, kiuj aperas en la ĉefa listo de la programo.
	 * Tiuj ĉi vortoj ne enhavas la ĉapelitajn esperantajn vortojn kiel {@link #vortoj_akcentitaj}.
	 * La ne akcentitaj vortoj estas uzitaj pro ordiga kialo: ne eblas norma ordigado
	 * kun esperantaj literoj. Do, nur uzante la x-sistemon, oni povas ordigi kaj
	 * serĉi kun la bisekcia metodo en la alfabete ordigita listo da vortoj.
	 */
	private String[] vortoj;
	/**
	 * La aro da ŝarĝitaj vortoj, kiuj aperas en la ĉefa listo de la programo.
	 * Male al {@link #vortoj} tiu ĉi aro enhavas la ĉapelitajn esperantajn vortojn.
	 * Ĝi utilas por la vidigado de la vortoj mem en la ĉefa listo de la programo.
	 */
	private String[] vortoj_akcentitaj;
	/**
	 * Enhavas la poziciojn de la vortoj enhavitaj de {@link #vortoj}
	 * en la dosiero, kiu enhavas la tutajn detalojn pri ĉiu tradukita vorto.
	 */
	private Long[] pozicioj;
	/**
	 * Enhavas la kodon, kiu montras ĉu la respondaj vortoj en la vektoro {@link #vortoj}
	 * estas unuope esperantaj, italaj aŭ sameskribitaj en ambaŭ lingvoj.
	 */
	private int[] koloroj;
	/**
	 * Tiu ĉi mapo rilatas la kodoj, kiuj aperas sub la formo de literoj,
	 * al la respondaj koloroj (kiuj estas same kiel hVortaro:
	 * "m"->"nigro", "v"->"lazuro/bluo", "w"->"verdo"
	 */
	private Map<Character,Integer> kolorMapo = new HashMap<Character,Integer>();
	private DBAdapter db;
	private boolean lasta = false;
	private boolean unua = true;
	/**
	 * Enhavas maksimume la tri komencajn literojn de la datumbazaj vortoj
	 * kun la respondaj pozicioj de la unuaj DB-aj vortoj, kiuj komencas
	 * per tiuj literoj.
	 */
	private Map<String,Integer> pozIndeksMapo = new HashMap<String,Integer>();
	private Map<Character,Integer> vortListoIndeksMapo = new HashMap<Character,Integer>();

	private final int MAKSIMUMA_HISTORIO = 100;
	private List<String> historio = new ArrayList<String>(MAKSIMUMA_HISTORIO);
	private List<Long> historio_poz = new ArrayList<Long>(MAKSIMUMA_HISTORIO);
	private List<String> historio_kol = new ArrayList<String>(MAKSIMUMA_HISTORIO);
	private final String HISTORIO_DOSIERO = "historio";
	private final int READ_BLOCK_SIZE = 100;
	private boolean ekzistas_historio = false;
	private ListView listo;
	private EditText teksto;
	private Button forigas;
	private ImageView bildo;
	private SharedPreferences agordoj;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        listo = (ListView) findViewById(R.id.listView_cxefaListo);
        teksto = (EditText) findViewById(R.id.editText_sercxilo);
        forigas = (Button) findViewById(R.id.button_forigas_cxefaListo);
        bildo = (ImageView)  findViewById(R.id.imageView_bildo);
        
        //sxargxasHistorion();
        new SxargxasHistorion().execute();
        
        //---agordas la kolorojn por la listo---
        kolorMapo.put('m', 0x40000000);
        kolorMapo.put('v', 0x400000FF);
        kolorMapo.put('w', 0x4000FF00);
        
        //---kreado de la mapon por ŝanĝi la skribmetodon---
        for(int j=0; j<S.cxapelitaj.length; j++){
        	S.literoj.put(S.necxapelitaj[j], S.cxapelitaj[j]);
        	S.literoj_x.put(S.cxapelitaj[j], S.necxapelitaj[j]);
        }
        
		//---kontrolas al ĉeeston de la DB---
        KontrolasDB("indekso.db");
        //---akiras la indekson kaj ŝarĝas pozIndeksMapo---
        db = new DBAdapter(this);
        pozIndeksado();
        	
        //---akiras la vortojn de la DB---
        sxargxasListon(listo);
        //new SxargxasListon().execute();
        
        agordoj = getSharedPreferences(getString(R.string.pref_agordoj), MODE_PRIVATE);
        plenumasAgordojn();
        
        listo.setOnScrollListener(new OnScrollListener(){
			public void onScroll(AbsListView view, int firstVisibleItem,
					int visibleItemCount, int totalItemCount) {
				// TODO Auto-generated method stub
				if(firstVisibleItem == totalItemCount - visibleItemCount){
					if(!lasta){
						startIndekso += vidIntervalo / 2;
						sxargxasListon((ListView)view);
						view.setSelection(vortoj.length/2);
					}
				}
				else if(firstVisibleItem == 1){
					int temp = startIndekso - vidIntervalo / 2;
					if(temp >= 0){
						startIndekso = temp;
						sxargxasListon((ListView)view);
						view.setSelection(vortoj.length/2);
					}
				}
			}
			public void onScrollStateChanged(AbsListView view, int scrollState) {}
        });
        
        listo.setOnItemClickListener(new OnItemClickListener(){
        	public void onItemClick(AdapterView arg0, View arg1,
        	     int position, long arg3) {
           		if(historio.contains(vortoj[position])){
           			int rem_idx = historio.indexOf(vortoj[position]);
           			historio.remove(rem_idx);
           			historio_poz.remove(rem_idx);
           			historio_kol.remove(rem_idx);
           		}
           		historio.add(0, vortoj[position]);
           		historio_poz.add(0, pozicioj[position]);
           		historio_kol.add(0, String.valueOf(koloroj[position]));
           		if(historio.size() == 101){
           			historio.remove(historio.size()-1);
           			historio_poz.remove(historio_poz.size()-1);
           			historio_kol.remove(historio_kol.size()-1);
           		}
           		Intent i = new Intent("verda.kvantumo.Itala_Esperanta_Vortaro.ARTIKOLO");
        	    Bundle extras = new Bundle();
        	    extras.putString("vorto", vortoj[position]);
        	    extras.putLong("pozicio", pozicioj[position]);
        	    i.putExtras(extras);
        	    startActivity(i);
        	}
        });
        
        teksto.addTextChangedListener(new TextWatcher(){
        	public void onTextChanged(CharSequence s, int start, int before, int count){
       			String nova = s.toString().trim();
       			if(!nova.equals("")){
       				forigas.setVisibility(View.VISIBLE);
       				for(String lit : S.literoj_x.keySet())
       					if(nova.contains(lit))
       						nova = nova.replace(lit, S.literoj_x.get(lit));
       				
       				if((nova.compareToIgnoreCase(vortoj[vortoj.length-1]) > 0 && vortoj[vortoj.length-1]!= "zuzzurellone")
       						|| (nova.compareToIgnoreCase(vortoj[0]) < 0	&& vortoj[0] != "a")){
       					lasta = false;
       					int idx;
       					if(nova.length() < 3)
       						if(pozIndeksMapo.containsKey(nova))
       							idx = pozIndeksMapo.get(nova);
       						else idx = -1;
       					else {
       						if(pozIndeksMapo.containsKey(nova.substring(0, 3))){
       							db.open();
       							idx = db.trovasID_dusekcado(nova, pozIndeksMapo.get(nova.substring(0, 3)));
       							db.close();
       						}
       						else idx = -1;
       					}
       					if(idx != -1){
       						startIndekso = idx - vidIntervalo/2;
       						if(startIndekso < 0)
       							startIndekso = 0;
       						else if(idx >= db.nombroElementoj()-101){
       							lasta = true;
       							startIndekso = db.nombroElementoj()-101;
       						}
       						sxargxasListon(listo);
       						if(startIndekso == 0)
       							listo.setSelection(0);
       						else if(startIndekso == db.nombroElementoj()-101){
       							listo.setSelection(idx - startIndekso);
       						}
       						else
       							listo.setSelection(vidIntervalo/2-1);
       					}
       				}
       				else{	// bisection method to find a word in the list
       					int ju, jm, j1;
       					boolean ascnd = true;
       					int n = vortoj.length;
       					j1 = -1;	// startas de 0 ĉar la vektora indekso startas de 0
       					ju = n;
       					while(ju - j1 > 1){
       						jm = (ju+j1) >> 1;
       						boolean b = (nova.compareToIgnoreCase(vortoj[jm])>=0);
       						if(b == ascnd)
       							j1 = jm;
       						else
       							ju = jm;
       					}
       					if(nova.equals(vortoj[0])) 
       						listo.setSelection(0);
       					else if(nova.equals(vortoj[n-1]))
       						listo.setSelection(n-1);
       					else
       						listo.setSelection(j1);
       				}
       			}
       			else
       				forigas.setVisibility(View.GONE);
        	}
        	public void afterTextChanged(Editable arg0){}
        	public void beforeTextChanged(CharSequence s, int arg1, int arg2, int arg3){}
        });
        
        //teksto.onWindowFocusChanged(ekzistas_historio);
        forigas.setOnClickListener(new OnClickListener(){
			public void onClick(View v) {
				teksto.setText("");
			}
        });
        
    }
    
    public void CopyDB(InputStream inputStream, OutputStream outputStream) throws IOException {
    	//---copy 1K bytes at a time---
    	byte[] buffer = new byte[1024];
    	int length;
    	while ((length = inputStream.read(buffer)) > 0) {
    		outputStream.write(buffer, 0, length);
    	}
    	inputStream.close();
    	outputStream.close();
   }
   
   /**
    * Kontrolas la ĉeesto de la datumbazo kaj de la dosierujo,
    * kiu devus enhavi ĝin.
    * Se ili ne ĉeestas, ĝi kreas ilin.
    * @param nomoDB nomo de la datumbazo
    */
   public void KontrolasDB(String nomoDB){
	   //---kontrolas al ĉeeston de la DB---
	   // Rimarku, ke la DB oni kontrolas, ĉu ekzistas la DB en la dosierujo
	   // /data/data/verda.kvantumo.Itala_Esperanta_Vortaro/databases/
	   String destPath = "/data/data/" + getPackageName() +
			   "/databases/";
	   String name_file = destPath + nomoDB;
	   File d = new File(destPath);
	   File f = new File(name_file);

	   if (!d.exists()) {	// se la dosierujo ne ĉeestas, tiam kreas ĝin
		   d.mkdir();            	
	   }
	   if (!f.exists()) {	// se la DB ne ĉeestas, tiam kopias la konservitan DB
		   try {
			   // Rimarku, ke la DB kopiinda estas en la dosierujo res/raw/ kaj
			   // ĝi nomiĝas "indekso.jpg". La kialo de ".jpg" estas eraro, kiu
			   // montriĝas por la versioj de Android antaŭ la 2.3.3.
			   // Fakte estas problemo kun la elpakado de la dosierujo kaj oni akiras
			   // la jena alerto:
			   // Data exceeds UNCOMPRESS_DATA_MAX
			   // Do, rapida solvo estas enmemorigi la DB kiel ".jpg" kaj dum la kopiado
			   // al la ĝusta dosierujo, la DB estas renomita kun ".db"
			   CopyDB( getBaseContext().getResources().openRawResource(R.raw.indekso),
					   new FileOutputStream(name_file));
		   } catch (NotFoundException e) {
			   // TODO Auto-generated catch block
			   e.printStackTrace();
		   } catch (FileNotFoundException e) {
			   // TODO Auto-generated catch block
			   e.printStackTrace();
		   } catch (IOException e) {
			   // TODO Auto-generated catch block
			   e.printStackTrace();
		   }
	   }
   
   }
   
   /**
    * Akiras la indekson de la DB kaj ŝarĝas {@link #pozIndeksMapo}
    */
   public void pozIndeksado(){
	   if(db != null){
		   db.open();
		   Cursor c = db.akirasIndekson();
		   if(c.getCount() != 0)
			{
			   do {
	            	pozIndeksMapo.put(c.getString(0), c.getInt(1));
			   } while (c.moveToNext());
			}
		   db.close();
	   }
	   else
		   Log.e(this.pozIndeksMapo.toString(),
				   "La adaptilo de la datumbazo devas esti komencita!", new Exception("@@"));
   }
   
   
   /**
    * Ŝarĝas ListView-n kun {@link #vidIntervalo} vortoj de la datumbazo,
    * startante de la vorto kun indekso=={@link #startIndekso}.
    * @param view la ListView, kiun oni volas ŝarĝi
    */
   public void sxargxasListon(ListView view){
	   db.open();
		// Se (startIndekso+vidIntervalo) preterpasas la totalan nombron da elementoj
		// en la DB ne gravas: la DB ĉiam redonos la eblajn elementojn.
		Cursor c = db.akirasIntervalon(startIndekso, startIndekso+vidIntervalo);
		if(c.getCount() != 0)
		{
			vortoj = new String[c.getCount()];
			vortoj_akcentitaj = new String[c.getCount()];
	        pozicioj  = new Long[c.getCount()];
	        koloroj =  new int[c.getCount()];
	        int q = 0;
	        if (c.moveToFirst())
	        {
	            do {
	            	vortoj[q] = c.getString(0).toLowerCase();
	            	pozicioj[q] = c.getLong(1);
	            	koloroj[q] = kolorMapo.get(c.getString(2).charAt(0));
	            	if(c.getString(2).charAt(0) == 'w')	// akcentas nur la Esperantajn vortojn
	            		vortoj_akcentitaj[q] = S.sxangxiLiterojn(vortoj[q]);
	            	else
	            		vortoj_akcentitaj[q] = vortoj[q];
	            	q++;
	            } while (c.moveToNext());
	        }
			view.setAdapter(new ColoredArrayAdapter(view.getContext(),
                   android.R.layout.simple_list_item_1, vortoj_akcentitaj, koloroj));
			// Se oni metas "vidIntervalo" anstataŭ "vortoj.length", estas danĝera,
			// ĉar ĉe la fino de la DB, la akiritaj vortoj ne estas perfekte vidIntervalo/2.
			//view.setSelection(vortoj.length/2);
		}
		db.close();
   }
   /**
    * Ŝarĝas la liston {@link #historio} kun la vortoj
    * enmemorigitaj de la antaŭaj serĉadoj.
    */
   public void sxargxasHistorion(){
	   try
	   {
		   BufferedReader in = new BufferedReader(new InputStreamReader(openFileInput(HISTORIO_DOSIERO)));
		   String temp;
		   String[] q;
		   while((temp = in.readLine()) != null){
			   q = temp.split(" @ ");
			   historio.add(q[0]);
			   historio_poz.add(Long.decode(q[1]));
			   historio_kol.add(q[2]);
		   }
	   }
	   catch (FileNotFoundException e) {
		   e.printStackTrace();
	   }
	   catch (IOException ioe) {
		   ioe.printStackTrace();
	   }
   }
   /**
    * Enmemorigas la liston {@link #historio} en dosiero
    * estonte relegebla.
    */
   public void skribasHistorion(){
	   try{
		   FileOutputStream fOut = openFileOutput(HISTORIO_DOSIERO, MODE_PRIVATE);
		   OutputStreamWriter osw = new OutputStreamWriter(fOut);
		   
		   for(int i=0; i<historio.size(); i++){
			   osw.write(historio.get(i) + " @ " + historio_poz.get(i) + " @ " + historio_kol.get(i) + "\n");
		   }
		   osw.flush();
		   osw.close();
	   }
	   catch (IOException ioe)
       {
           ioe.printStackTrace();
       }
   }
   
   public void plenumasAgordojn(){
	   if(!agordoj.getBoolean(S.AGORDOJ_FONO, true))
		   bildo.setVisibility(View.GONE);
	   else
		   bildo.setVisibility(View.VISIBLE);
   }
   
   /**
    * Enmemorigas la liston {@link #historio} de la serĉitaj vortoj dosieren. 
    */
   @Override
   protected void onDestroy() {
	   skribasHistorion();
	   super.onDestroy();
   }
   @Override
   protected void onResume(){
	   teksto.selectAll();
	   super.onResume();
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
   	MenuInflater inflater = getMenuInflater();
       inflater.inflate(R.menu.menu_main, menu);
       return true;
   }
   @Override
   public boolean onOptionsItemSelected(MenuItem item)
   {
   	switch(item.getItemId()) {
       case R.id.item_historio:
    	   if(historio.size() != 0){ // la historio enhavas kelkan vorton...
    		   // montras la liston de la serĉitaj vortoj
	    	   Intent a = new Intent("verda.kvantumo.Itala_Esperanta_Vortaro.HISTORIO");
	    	   Bundle b = new Bundle();
	    	   String[] s = new String[historio.size()];
	    	   String[] k = new String[historio_kol.size()];
	    	   Integer[] i = new Integer[historio_kol.size()];
	    	   b.putSerializable("vortoj", historio.toArray(s));
	    	   b.putSerializable("koloroj", historio_kol.toArray(k));
	    	   
	    	   long[] l = new long[historio_poz.size()];
	    	   for(int j=0; j<l.length; j++)
	    		   l[j] = historio_poz.get(j).longValue();
	    	   b.putSerializable("pozicioj", l);
	    	   
	    	   a.putExtras(b);
	    	   startActivityForResult(a, 1);
    	   }
    	   else	// ... la historio malplenas
    		   Toast.makeText(getBaseContext(), getString(R.string.historio_malplena), Toast.LENGTH_SHORT).show();
           return true;
       case R.id.item_agordoj:
    	   startActivityForResult(new Intent("verda.kvantumo.Itala_Esperanta_Vortaro.AGORDOJ"), 2);
    	   return true;
       case R.id.item_gramatiko:
    	   startActivity(new Intent("verda.kvantumo.Itala_Esperanta_Vortaro.GRAMATIKO_LISTO"));
    	   return true;
       case R.id.item_pri:
    	   startActivity(new Intent("verda.kvantumo.Itala_Esperanta_Vortaro.PRI"));
    	   return true;
       default:
           break;
       }
    
       return true;
   }
   @Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if(requestCode == 1){
			if(resultCode == RESULT_OK){
				if(data.getData().toString().equals("forigu")){
					historio.clear();
					historio_poz.clear();
					historio_kol.clear();
					Toast.makeText(getBaseContext(), getString(R.string.forigita), Toast.LENGTH_SHORT).show();
				}
			}
		}
		else if(requestCode == 2){
			plenumasAgordojn();
/*			if(resultCode == RESULT_OK){
				if(data.getData().toString().equals("true")){
					plenumasAgordojn();
				}
			}*/
		}
	}

   private class SxargxasHistorion extends AsyncTask<String, Void, Object> {
       protected List<String> doInBackground(String... args) {
    	   try
    	   {
    		   BufferedReader in = new BufferedReader(new InputStreamReader(openFileInput(HISTORIO_DOSIERO)));
    		   String temp;
    		   String[] q;
    		   while((temp = in.readLine()) != null){
    			   q = temp.split(" @ ");
    			   historio.add(q[0]);
    			   historio_poz.add(Long.decode(q[1]));
    			   historio_kol.add(q[2]);
    		   }
    		   //findViewById(R.id.item_historio).setEnabled(true);
    	   }
    	   catch (FileNotFoundException e) {
    		   e.printStackTrace();
    	   }
    	   catch (IOException ioe) {
    		   ioe.printStackTrace();
    	   }
    	   return historio;
       }

       protected void onPostExecute(Object result) {
           // Pass the result data back to the main activity
       }
  }
   
  private class SxargxasListon extends AsyncTask<String, Void, Object> {
       protected Object doInBackground(String... args) {
    	   sxargxasListon(listo);
    	   return 0;
       }

       protected void onPostExecute(Object result) {
           // Pass the result data back to the main activity
           //Artikolo.this.testo = result;
       }
  }
}